package com.aiwiown.snackmq.storage.util;

import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;

/**
 * 一个用于安全清理 DirectByteBuffer 和 MappedByteBuffer 的工具类。
 * 它通过反射调用内部的 cleaner 方法来释放与 ByteBuffer 关联的堆外内存或文件映射。
 * 这是处理 MappedByteBuffer 在 Windows 上文件锁定问题的关键。
 * 该实现专注于 JDK 8，但也包含了对更高版本的兼容性考虑。
 */
@Slf4j
public final class BufferCleaner {

    private static final Method GET_CLEANER_METHOD;
    private static final Method CLEAN_METHOD;

    static {
        Method getCleaner = null;
        Method clean = null;
        try {
            // 适用于 Java 8 的方法 (sun.misc.Cleaner)
            Class<?> directBufferClass = Class.forName("java.nio.DirectByteBuffer");
            getCleaner = directBufferClass.getMethod("cleaner");
            getCleaner.setAccessible(true);
            Class<?> cleanerClass = Class.forName("sun.misc.Cleaner");
            clean = cleanerClass.getMethod("clean");
            clean.setAccessible(true);
            log.debug("成功初始化 Java 8 的 ByteBuffer 清理器。");
        } catch (Exception e) {
            log.warn("无法初始化 ByteBuffer 清理器。在非 HotSpot/OpenJDK 的 JVM 上或在严格的安全管理器下，这可能是正常的。", e);
        }
        GET_CLEANER_METHOD = getCleaner;
        CLEAN_METHOD = clean;
    }

    private BufferCleaner() {
    }

    /**
     * 尝试清理给定的 ByteBuffer。
     * 如果 ByteBuffer 不是 Direct 或 Mapped 类型，此方法将不执行任何操作。
     *
     * @param buffer 要清理的 ByteBuffer
     * @return 如果成功发起了清理操作，则返回 true
     */
    public static boolean clean(final ByteBuffer buffer) {
        if (buffer == null || !buffer.isDirect()) {
            return false;
        }

        if (CLEAN_METHOD == null || GET_CLEANER_METHOD == null) {
            log.warn("ByteBuffer 清理器未被正确初始化，无法执行清理操作。");
            return false;
        }

        try {
            Object cleaner = GET_CLEANER_METHOD.invoke(buffer);
            if (cleaner != null) {
                CLEAN_METHOD.invoke(cleaner);
                log.debug("成功调用反射方法清理了 ByteBuffer。");
                return true;
            }
        } catch (Exception e) {
            log.warn("清理 ByteBuffer 失败。", e);
        }
        return false;
    }
}